home *** CD-ROM | disk | FTP | other *** search
- #define noVDEBUG
- #define nDEBUG
- #define nDEBUGA
- #define xDEBUGSEQ
- #define noDEBUGPKT
- #define xDEBUGWR
- #define noDEBUGWA
- #define nDEBUGS
- #define nDEBUGPS
- #define noDEBUGRST
- #define yDEBUGW
- #define nDEBUGRWIN
- #define noRTDEBUG
- #define noDEBUGPRT
- #define xDEBUGTIMEW
- #define noDEBUGBUF
- #define xDEBUGSENDCALL
-
- #define ACKWRONG
- #define nREQUEUE
-
- #include <stdio.h>
-
- #ifdef DEBUG
- #include <string.h>
- #endif
-
- #include <stdlib.h>
- #include <time.h>
- #include "pktdrv.h"
- #include "ip.h"
- #include "tcp.h"
- #include "timer.h"
- #include "inetcust.h"
- #include "mbuf.h"
-
- #ifdef DEBUG
- #include "cookie.h"
- #include "nettrace.h"
- static char str[200];
- #endif
-
- #define max(a,b) ((a) > (b) ? (a) : (b))
- #define min(a,b) ((a) < (b) ? (a) : (b))
- #define abs(a) ((a) > 0 ? (a) : (-a))
-
- TCP_TCB *tcpcb_list = NULL;
- TCP_TCB **tcpcb_tab = NULL;
- static int tcpcb_tablen = 0;
- extern char *tcp_buffers;
- int tcpcb_needack = -1;
- static TIMER tcp_expedit;
- extern int mode;
- long tcp_counts[2] = {0L,0L};
-
- long INBUFBASE, OUTBUFSIZE;
-
- #define tcp_iss() clock() & 0xffffL;
-
- static int tcp_reset(PACKET *,int,INADDR,u_short);
- void tcp_opentimeout(TIMER);
- void tcp_acktimeout(TIMER);
- void tcp_timewait(TIMER);
- void tcp_expedittm(TIMER);
- static int tcp_send(TCP_TCB *tcpcb);
- static TCP_SEGMENT *tcp_createseg(u_long length, u_long seq,u_char flags);
- static int tcp_putseg(TCP_TCB *tcpcb,TCP_SEGMENT *tcp_seg);
- static int tcp_updateseg(TCP_TCB *tcpcb);
- static int tcp_reseg(TCP_TCB *tcpcb);
- int tcp_handler(PACKET *pkt, int length, INADDR fhost);
- int tcp_du_handler(IP *ip);
- u_short tcp_newport(void);
- void tcp_retransmitter(TIMER);
- u_short tcp_rcvwindow(TCP_TCB *);
-
- #ifdef DEBUG
- char *pr_flags(u_char);
- char *pr_state(TCP_TCB *);
- #endif
-
- int tcp_init(void)
- {
- register int i;
- char *value;
-
- value = (char *)getenv("INBUFBASE");
- if(value) INBUFBASE = atol(value);
- else INBUFBASE = 0L;
-
- value = (char *)getenv("OUTBUFSIZE");
- if(value) OUTBUFSIZE = atol(value);
- else OUTBUFSIZE = MIN_OUTBUFSIZE;
-
- tcpcb_list = NULL;
- tcpcb_tablen = TCP_DEFMAXTCPS;
- tcpcb_tab = (TCP_TCB **)getmem((size_t)tcpcb_tablen*sizeof(TCP_TCB *));
- if(!tcpcb_tab) return(FALSE);
- for(i=0; i<tcpcb_tablen; i++)
- tcpcb_tab[i] = NULL;
- tcpcb_list = NULL;
- if(!ip_open(IP_TCP,tcp_handler,tcp_du_handler))
- {
- freemem(tcpcb_tab);
- return(FALSE);
- }
-
- tcp_expedit = tm_alloc();
- /*
- tm_set(TCP_EXPEDIT,tcp_expedittm,tcp_expedit);
- */
- return(TRUE);
- }
-
- int tcp_exit(void)
- {
- int i;
- if(tcpcb_tab)
- {
- for(i=0;i<tcpcb_tablen;i++)
- if(tcpcb_tab[i]) tcp_delete(i);
- freemem(tcpcb_tab);
- tcpcb_tab = NULL;
- tcpcb_tablen = 0;
- }
- return(ip_close(IP_TCP));
- }
-
- /********************************/
- /* process incoming tcp-packets */
- /********************************/
-
- int tcp_handler(PACKET *pkt,int len,INADDR fhost)
- {
- TCP_PSEUDO tcp_ph;
- TCP *tcp;
- IP *ip;
- TCP_TCB *tcpcb;
- TCP_SEGMENT *tcp_seg;
- u_short csum;
- char *data;
-
- #ifdef DEBUG
- TRACE(">tcp_handler\n");
- #endif
- ip = ip_head(pkt);
- tcp = (TCP *)ip_data(pkt);
-
- tcp_ph.dst = ip->dst_inaddr;
- tcp_ph.src = fhost;
- tcp_ph.protocol = IP_TCP;
- tcp_ph.length = len;
-
- csum = tcp->chksum;
- tcp->chksum = ~chksum((u_short *)&tcp_ph,(int)sizeof(TCP_PSEUDO),0);
- tcp->chksum = chksum((u_short *)tcp,len,0);
- if(csum != tcp->chksum && !(csum == 0xffff && tcp->chksum == 0))
- {
- #ifdef DEBUG
- TRACE("<tcp_handler: bad checksum\n");
- #endif
- ip_free(pkt); /* bad checksum, drop packet */
- return(FALSE);
- }
- tcp->chksum = csum;
- #ifdef DEBUGP
- sprintf(str," tcp_handler: to l_%u from f_%u, %s\n",tcp->dst_port,tcp->src_port,pr_flags(tcp->flags));
- TRACE(str);
- #endif
- tcp_counts[0]++;
- /* demux to active tcpcb's */
- for(tcpcb = tcpcb_list; tcpcb; tcpcb = tcpcb->next)
- {
- if( tcpcb->active &&
- tcp->dst_port == tcpcb->lcl_port &&
- tcp->src_port == tcpcb->fgn_port &&
- fhost == tcpcb->fhost)
- break;
- }
- if(!tcpcb) for(tcpcb = tcpcb_list; tcpcb; tcpcb = tcpcb->next)
- { /* demux to listening ports */
- if( !tcpcb->active &&
- tcp->dst_port == tcpcb->lcl_port)
- break;
- }
- if(!tcpcb || tcpcb->state == TCP_CLOSED)
- { /* no one wants packet */
- #ifdef DEBUG
- sprintf(str,"<tcp_handler: ? %lx at port l_%u.f_%u\n",fhost,tcp->dst_port,tcp->src_port);
- TRACE(str);
- #endif
- tcp_reset(pkt,len,fhost,tcp->dst_port); /* send a reset back*/
- ip_free(pkt);
- return(FALSE);
- }
- #ifdef DEBUG
- sprintf(str," tcp_handler: l_%u.f_%u: pkt[%d] recnxt=%lx,\n... seq=%lx, fl=%s st=%s\n",tcp->dst_port,tcp->src_port,len,tcpcb->rcvnxt,tcp->seq,pr_flags(tcp->flags),pr_state(tcpcb));
- TRACE(str);
- #endif
-
- switch(tcpcb->state)
- {
- case TCP_LISTEN:
- if(tcp->flags & TCP_RST)
- {
- ip_free(pkt); /* ignore RST packet */
- return(FALSE);
- }
- if(tcp->flags & TCP_ACK)
- {
- tcp_reset(pkt,len,fhost,tcp->dst_port); /* ack is invalid */
- ip_free(pkt);
- return(FALSE);
- }
- if(tcp->flags & TCP_SYN)
- {
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: TCP_LISTEN + SYN received -> SYNREC state\n");
- #endif
- tcpcb->rcvnxt = tcp->seq+1;
- tcpcb->sndwnd = tcp->window;
- tcpcb->sndiss = tcp_iss();
- tcpcb->sndact = tcpcb->sndiss;
- tcpcb->fhost = fhost;
- tcpcb->fgn_port = tcp->src_port;
- tcpcb->state = TCP_SYNREC;
- if(tcp_getopt(tcp) < tcpcb->maxseg)
- tcpcb->maxseg = tcp_getopt(tcp);
- tcp_seg = tcp_createseg(0,tcpcb->sndiss,TCP_SYN | TCP_ACK);
- tcp_putseg(tcpcb,tcp_seg); /* put segment in retransmission queue */
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: call send for SYNACK\n");
- #endif
- tcp_send(tcpcb);
- tcpcb->sndnxt = tcpcb->sndiss+1;
- tcpcb->snduna = tcpcb->sndiss;
- }
- ip_free(pkt);
- return(TRUE);
-
- case TCP_SYNSENT:
- if(tcp->flags & TCP_ACK)
- {
- if(SEQ_LE(tcp->ack,tcpcb->sndiss) ||
- SEQ_GT(tcp->ack,tcpcb->sndnxt))
- {
- tcp_reset(pkt,len,fhost,tcp->dst_port); /* ack is invalid */
- ip_free(pkt);
- return(FALSE);
- }
- }
-
- if(tcp->flags & TCP_RST)
- {
- if(tcp->flags & TCP_ACK)
- {
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCRESET);*/
- tm_stop(tcpcb->tcp_tm);
- #ifdef DEBUGCONN
- TRACE("<tcp_handler: delete on ACK/RST\n");
- #endif
- tcp_delete(tcpcb->handle);
- }
- ip_free(pkt);
- return(FALSE);
- }
-
- if(tcp->flags & TCP_SYN)
- {
- tcpcb->rcvnxt = tcp->seq+1L;
- tcpcb->rcvirs = tcp->seq;
- tcpcb->snduna = tcp->ack;
- tcp_updateseg(tcpcb);
- if(tcp_getopt(tcp) < tcpcb->maxseg)
- tcpcb->maxseg = tcp_getopt(tcp);
- tcpcb->sndwnd = tcp->window;
- if(SEQ_GT(tcpcb->snduna,tcpcb->sndiss))
- {
- tcpcb->state = TCP_ESTAB;
- tcp_seg = tcp_createseg(0,tcpcb->sndnxt,TCP_ACK);
- tcp_putseg(tcpcb,tcp_seg);
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: call send for SYNSENTACK\n");
- #endif
- tcp_send(tcpcb);
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCESTAB);*/
- tm_stop(tcpcb->tcp_tm);
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: TCP_SYNSENT -> entering ESTAB state\n");
- #endif
- }
- else
- {
- tcpcb->state = TCP_SYNREC;
- tcp_seg = tcp_createseg(0,tcpcb->sndnxt,TCP_SYN | TCP_ACK);
- tcp_putseg(tcpcb,tcp_seg); /* put segment in retransmission queue */
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: call send for SYNSENTSYNACK\n");
- #endif
- tcp_send(tcpcb);
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: entering SYNREC state\n");
- #endif
- }
- }
- ip_free(pkt);
- return(FALSE);
- } /* end switch */
-
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: more than SYNREC\n");
- #endif
- len -= tcp_hdrlen(tcp);
-
- if(tcp->flags & TCP_RST)
- {
- if(tcpcb->state == TCP_SYNREC)
- {
- if(tcpcb->active)
- {
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCRESET);*/
- tm_stop(tcpcb->tcp_tm);
- }
- else
- {
- tcpcb->state = TCP_LISTEN;
- }
- ip_free(pkt);
- return(FALSE);
- }
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCCLOSED);*/
- #ifdef DEBUGCONN
- TRACE("<tcp_handler: delete on RST\n");
- #endif
- tcp_delete(tcpcb->handle);
- ip_free(pkt);
- return(FALSE);
- }
-
- if(/*!(tcp->flags & TCP_RST) &&*/
- ((!tcpcb->rcvwnd && (len || tcp->seq != tcpcb->rcvnxt)) ||
- #ifndef REQUEUE
- (SEQ_GT(tcp->seq,tcpcb->rcvnxt)) ||
- #endif
- (len && SEQ_LE((tcp->seq + len),tcpcb->rcvnxt))))
- {
- #ifdef DEBUG
- sprintf(str," tcp_handler: seq not expected pkt = %lx: seq= %lx, rcvnxt=%lx, len = %u\n",
- (long)pkt,tcp->seq,tcpcb->rcvnxt,len);
- TRACE(str);
- #endif
- ip_free(pkt);
-
- #ifdef ACKWRONG
- tcp_seg = tcp_createseg(0,tcpcb->sndnxt,TCP_ACK);
- tcp_putseg(tcpcb,tcp_seg); /* put segment in retransmission queue */
- tcp_send(tcpcb);
- #ifdef DEBUG
- TRACE("<tcp_handler: called send for out of seq nack\n");
- #endif
- #endif
- return(FALSE);
- }
- #ifdef REQUEUE
- if (SEQ_GT(tcp->seq,tcpcb->rcvnxt))
- {
- #ifdef DEBUG
- sprintf(str,"<tcp_handler: requeuing packet seq= %lx, rcvnxt=%lx, len = %d\n",tcp->seq,tcpcb->rcvnxt,len);
- TRACE(str);
- #endif
- if(!ip_requeue(pkt)) /* put packet to end of receive queue to delay processing */
- ip_free(pkt); /* all free packets used, so drop this pkt */
- return(FALSE);
- }
- #endif
-
-
- if(tcp->flags & TCP_SYN)
- {
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCCLOSED);*/
- /* TRACE("<tcp_handler: delete on SYN\n");
- tcp_delete(tcpcb->handle);*/
- ip_free(pkt);
- return(FALSE);
- }
- if(!(tcp->flags & TCP_ACK)) /* MISSING ACK */
- {
- #ifdef DEBUG
- TRACE("<tcp_handler: missing ACK\n");
- #endif
- ip_free(pkt);
- return(FALSE);
- }
-
- if(tcpcb->state == TCP_SYNREC)
- {
- if(SEQ_LE(tcpcb->snduna,tcp->ack) &&
- SEQ_LE(tcp->ack,tcpcb->sndact))
- {
- #ifdef DEBUGCONN
- TRACE(" tcp_handler: TCP_SYNREC-> entering ESTAB state\n");
- #endif
- tcpcb->state = TCP_ESTAB;
- if(!len)
- {
- tcpcb->active = TRUE; /* continue processing */
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCESTAB);*/
- }
- }
- else
- {
- #ifdef DEBUGCONN
- sprintf(str,"<tcp_handler: TCP_SYNREC invalid ack %lx, sending reset \n",tcp->ack);
- TRACE(str);
- #endif
- tcp_reset(pkt,len,fhost,tcp->dst_port);
- ip_free(pkt); /* invalid ack */
- return(FALSE);
- }
- }
- if(tcpcb->state == TCP_ESTAB ||
- tcpcb->state == TCP_FINWT1 ||
- tcpcb->state == TCP_FINWT2 ||
- tcpcb->state == TCP_LASTACK ||
- tcpcb->state == TCP_CLOSING ||
- tcpcb->state == TCP_CLOSEWT)
- {
- #ifdef DEBUG
- sprintf(str," tcp_handler: TCP_ESTAB snd.una = %lx seg.ack=%lx snd.nxt %lx sndact %lx\n",tcpcb->snduna,tcp->ack,tcpcb->sndnxt,tcpcb->sndact);
- TRACE(str);
- #endif
- if(SEQ_GT(tcp->ack,tcpcb->sndact))
- {
- #ifdef DEBUG
- TRACE(" tcp_handler: peer is acking unsent data !!\n");
- #endif
- ip_free(pkt);
- tcp_seg = tcp_createseg(0,tcpcb->sndnxt,TCP_ACK);
- tcp_putseg(tcpcb,tcp_seg);
- #ifdef DEBUGCONN
- sprintf(str,"<tcp_handler: call send for unack \n");
- TRACE(str);
- #endif
- tcp_send(tcpcb);
- return(FALSE);
- }
-
- if(SEQ_LT(tcpcb->snduna,tcp->ack)) /* new ack arrived */
- {
- tcpcb->snduna = tcp->ack;
- /*#ifdef DEBUG
- TRACE(" tcp_handler: update resendqueue on ack\n");
- #endif
- tcp_updateseg(tcpcb); /* update resendqueue */
- */
- switch(tcpcb->state)
- {
- case TCP_LASTACK:
- if(tcpcb->snduna == tcpcb->finack)
- {
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCCLOSED);*/
- #ifdef DEBUGCONN
- TRACE("<tcp_handler: delete in LASTACK\n");
- #endif
- tcp_delete(tcpcb->handle);
- }
- case TCP_CLOSING:
- if(tcpcb->snduna == tcpcb->finack)
- {
- tcpcb->state = TCP_TIMEWT;
- #ifdef DEBUGTIMEW
- TRACE(" tcp_handler: TCP_CLOSING ->timewait clock set\n");
- #endif
- tm_stop(tcpcb->tcp_tm);
- tm_set(TCP_WAITTIMEOUT,tcp_timewait,tcpcb->tcp_tm);
- }
- break;
- case TCP_FINWT1:
- if(tcpcb->snduna == tcpcb->finack)
- tcpcb->state = TCP_FINWT2;
- break;
- }
- }
-
- if(SEQ_LE(tcpcb->snduna,tcp->ack))
- {
- if(SEQ_LT(tcpcb->sndwl1,tcp->seq) ||
- (tcpcb->sndwl1 == tcp->seq && SEQ_LE(tcpcb->sndwl2,tcp->ack)))
- {
- if(tcpcb->sndmax < tcp->window)
- tcpcb->sndmax = tcp->window;
- tcpcb->sndest = (u_short)(tcpcb->sndact - tcpcb->snduna);
- if(tcp->window > tcpcb->sndest)
- tcpcb->sndest = tcp->window - tcpcb->sndest;
- else
- tcpcb->sndest = 0;
-
- tcpcb->sndwnd = tcp->window;
-
- tcpcb->sndwl1 = tcp->seq;
- tcpcb->sndwl2 = tcp->ack;
- #ifdef DEBUGWA
- sprintf(str," tcp_handler: updating sendwindow, now got %d, est %d used %d \n",tcp->window, tcpcb->sndest, tcpcb->sndwnd);
- TRACE(str);
- #endif
- }
- }
-
- if( tcpcb->state == TCP_SYNREC ||
- tcpcb->state == TCP_ESTAB ||
- tcpcb->state == TCP_FINWT1 ||
- tcpcb->state == TCP_FINWT2)
- {
- data = (char *)tcp + tcp_hdrlen(tcp);
- if(SEQ_LT(tcp->seq,tcpcb->rcvnxt) &&
- SEQ_GT(tcp->seq+len,tcpcb->rcvnxt))
- {
- data += tcpcb->rcvnxt - tcp->seq;
- len -= (int)(tcpcb->rcvnxt - tcp->seq);
- }
-
- if(len && tcpcb->q_in.size)
- {
- len = (int)q_put(&tcpcb->q_in,(u_char *)data,len);
- #ifdef DEBUG
- sprintf(str," tcp_handler: queued %d bytes, rd = %lx wr = %lx\n",
- len,(&tcpcb->q_in)->rd,(&tcpcb->q_in)->wr);
- TRACE(str);
- #endif
- if(q_used(&tcpcb->q_in) > tcpcb->rcvdlen)
- tcpcb->rcvdlen = q_used(&tcpcb->q_in);
- tcpcb->rcvnxt += len;
- #ifdef DEBUGSEQ
- sprintf(str," tcp_handler: updated rcvnxt, now %lx (+%ld)\n",tcpcb->rcvnxt,(long)len);
- TRACE(str);
- #endif
- }
- tcpcb->rcvwnd = tcp_rcvwindow(tcpcb);
-
- if(!tcpcb->active)
- {
- tcpcb->active = TRUE;
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCESTAB);*/
- }
- /*if(tcpcb->q_in.size && len && (tcp->flags & TCP_PUSH
- || tcpcb->rcvwnd < (tcpcb->q_in.size * 3) / 4))
- tcpcb->upcall(tcpcb->handle,NULL,TCP_UCDATA)*/; /* tell user new data is there */
-
- if(len)
- {
- #ifdef DEBUG
- TRACE(" tcp_handler: create delayed ack_segment\n");
- #endif
- tcp_seg = tcp_createseg(0,tcpcb->sndnxt,TCP_ACK);
- tcp_putseg(tcpcb,tcp_seg);
- tm_stop(tcpcb->tcp_ack);
- tm_stop(tcpcb->tcp_tmresend);
- /*tcp_acktimeout*/(tm_set(TCP_NODELAY,tcp_acktimeout,tcpcb->tcp_ack));
- /* deliver ack immediately after reading IP-TCP input */
- }
- }
- }
-
- if(tcp->flags & TCP_FIN)
- {
- switch(tcpcb->state)
- {
- case TCP_SYNREC:
- case TCP_ESTAB:
- tcpcb->rcvnxt++; /* consume FIN */
- tcpcb->state = TCP_CLOSEWT;
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCCLOSEWT);*/
- break;
-
- case TCP_FINWT1:
- tcpcb->rcvnxt++; /* consume FIN */
- if(tcpcb->finack != tcpcb->snduna)
- tcpcb->state = TCP_CLOSING;
- else
- {
- tcpcb->state = TCP_TIMEWT;
- tm_stop(tcpcb->tcp_tm);
- tm_set(TCP_WAITTIMEOUT,tcp_timewait,tcpcb->tcp_tm);
- }
- break;
- case TCP_FINWT2:
- tcpcb->rcvnxt++; /* consume FIN */
- tcpcb->state = TCP_TIMEWT;
- tm_stop(tcpcb->tcp_tm);
- tm_set(TCP_WAITTIMEOUT,tcp_timewait,tcpcb->tcp_tm);
- break;
- case TCP_TIMEWT:
- #ifdef DEBUGTIMEW
- TRACE(" tcp_handler: TCP_FINWT2 -> timewait clock set\n");
- #endif
- tm_stop(tcpcb->tcp_tm);
- tm_set(TCP_WAITTIMEOUT,tcp_timewait,tcpcb->tcp_tm);
- break;
- case TCP_CLOSEWT:
- case TCP_CLOSING:
- case TCP_LASTACK:
- /* remain in state */
- break;
- }
- tcp_seg = tcp_createseg(0,tcpcb->sndnxt,TCP_ACK);
- tcp_putseg(tcpcb,tcp_seg);
- #ifdef DEBUGSENDCALL
- sprintf(str," tcp_handler: call send for (FIN)ACK \n");
- TRACE(str);
- #endif
- tcp_send(tcpcb);
- }
- ip_free(pkt);
- #ifdef DEBUG
- TRACE("<tcp_handler\n");
- #endif
- return(FALSE);
- }
-
- static TCP_SEGMENT *tcp_createseg(u_long length,u_long seq, u_char flags)
- {
- TCP_SEGMENT *seg;
-
- #ifdef DEBUG
- TRACE(">tcp_createseg\n");
- #endif
- seg = (TCP_SEGMENT *)getmem(sizeof(TCP_SEGMENT));
- if(!seg)
- {
- #ifdef DEBUG
- TRACE("<tcp_createseg, out of mem\n");
- #endif
- return(NULL);
- }
- seg->next = NULL;
- seg->seq = seq;
- seg->flags = flags | TCP_UNSENT;
- seg->length = length;
- #ifdef DEBUG
- TRACE("<tcp_createseg,ok\n");
- #endif
- return(seg);
- }
-
- int tcp_putseg(TCP_TCB *tcpcb,TCP_SEGMENT *tcp_seg)
- {
- TCP_SEGMENT **q;
- u_long seq;
-
- #ifdef DEBUG
- TRACE(">tcp_putseg\n");
- #endif
-
- q = &tcpcb->resend;
- if(*q) seq = (*q)->seq;
- while(*q)
- {
- seq += (*q)->length;
- if((*q)->flags & (TCP_SYN | TCP_FIN)) seq++;
-
- if(!((*q)->flags & (TCP_SYN | TCP_PUSH | TCP_FIN)) &&
- tcp_seg->seq == seq) /* segment can be combined */
- {
- #ifdef DEBUG
- sprintf(str," tcp_putseg: combining segments, size %ld, now %ld, flags = %s, seq = %lx\n",(*q)->length, (*q)->length,pr_flags((*q)->flags) + tcp_seg->length,tcp_seg->seq);
- TRACE(str);
- #endif
- (*q)->length += tcp_seg->length;
- (*q)->flags |= tcp_seg->flags;
- freemem(tcp_seg);
- #ifdef DEBUG
- TRACE("<tcp_putseg\n");
- #endif
- return(TRUE);
- }
- q = &((*q)->next); /* find end of list */
- }
- *q = tcp_seg; /* put at end of list */
- #ifdef DEBUG
- TRACE("<tcp_putseg\n");
- #endif
- return(TRUE);
- }
-
- static int tcp_updateseg(TCP_TCB *tcpcb)
- {
- register TCP_SEGMENT *tcp_seg;
- long drop;
- #ifdef DEBUG
- TRACE(">tcp_updateseg\n");
- #endif
-
- if(!tcpcb->resend)
- {
- #ifdef DEBUG
- TRACE("<tcp_updateseg: currently no sendqueue\n");
- #endif
- return(FALSE);
- }
-
- tcp_seg = tcpcb->resend;
-
- while(tcp_seg)
- {
- if(SEQ_GT(tcpcb->snduna,tcp_seg->seq))
- { /* part or all of segment is acked */
- if(!tcp_seg->length ||
- SEQ_LE(tcp_seg->seq + tcp_seg->length,tcpcb->snduna) )
- { /* all of segment is acked */
- #ifdef DEBUG
- sprintf(str," tcp_updateseg: skip acked seg len = %ld\n",tcp_seg->length);
- TRACE(str);
- #endif
- tcpcb->resend = tcp_seg->next; /* new start of resend queue */
- if(tcp_seg->length)
- q_rem(&tcpcb->q_out,tcp_seg->length); /* dequeue acked data */
- freemem(tcp_seg);
- tcp_seg = tcpcb->resend;
- }
- else /* segment has data, but not all is acked */
- {
- #ifdef DEBUG
- TRACE(" tcp_updateseg: skip some acked data\n");
- #endif
- drop = tcpcb->snduna - tcp_seg->seq;
- q_rem(&tcpcb->q_out,drop); /* remove from start of queue */
- tcp_seg->length -= drop;
- tcp_seg->seq = tcpcb->snduna;
- break; /* keep segment in queue */
- }
- }
- else break;
- }
- if(!tcpcb->resend) tm_stop(tcpcb->tcp_tmresend);
- #ifdef DEBUG
- TRACE("<tcp_updateseg\n");
- #endif
-
- return(TRUE);
- }
-
- static int tcp_send(TCP_TCB *tcpcb)
- {
- PACKET *pkt;
- TCP_PSEUDO tcp_ph;
- TCP_SEGMENT *tcp_seg, **tcp_lastseg;
- TCP *tcp;
- char *data;
- u_short csum;
- u_long length;
- int ret,send_mult;
- u_long offset;
- int tmpflags;
- int loop;
-
- #ifdef VDEBUG
- TRACE(">tcp_send\n");
- #endif
-
- if(!tcpcb) /* tcpcb does not exist */
- {
- #ifdef DEBUG
- TRACE("<tcp_send: tcpcb does not exist - exit\n");
- #endif
- return(-1);
- }
-
- #ifdef DEBUGS
- sprintf(str," tcp_send: l_%u.f_%u\n",tcpcb->lcl_port,tcpcb->fgn_port);
- TRACE(str);
- #endif
-
- tcp_updateseg(tcpcb); /* remove already acked data */
-
- offset = 0;
- tcp_seg = tcpcb->resend;
- tcp_lastseg = &tcpcb->resend;
-
- while(tcp_seg && SEQ_LT(tcp_seg->seq + tcp_seg->length,tcpcb->sndact))
- {
- #ifdef DEBUG
- sprintf(str," tcp_send: skipping already sent segment %lx...%lx < act = %lx\n",tcp_seg->seq,tcp_seg->seq + tcp_seg->length,tcpcb->sndact);
- TRACE(str);
- #endif
- offset += tcp_seg->length;
- tcp_lastseg = &tcp_seg->next;
- tcp_seg = tcp_seg->next;
- }
-
- if(!tcp_seg)
- {
- #ifdef DEBUG
- TRACE("<tcp_send: nothing to send - exit\n");
- #endif
- return(0);
- }
-
- offset += tcpcb->sndact - tcp_seg->seq;
-
- #ifdef DEBUG
- sprintf(str," tcp_send: skip %ld sent bytes in segment\n",tcpcb->sndact - tcp_seg->seq);
- TRACE(str);
- #endif
-
- for(loop = 0;loop < 4;loop++)
- {
-
- send_mult = 0;
- length = (tcp_seg->seq + tcp_seg->length) - tcpcb->sndact;
-
- if(length > tcpcb->maxseg)
- {
- send_mult = 1;
- length = tcpcb->maxseg;
- }
-
- tmpflags = tcp_seg->flags;
-
- if(length)
- { /* don't exceed window of partner */
- if(tcpcb->sndwnd == 0)
- {
- length = 1; /* if window is zero, send at least one databyte */
- tmpflags &= ~(TCP_PUSH | TCP_URG | TCP_FIN);
- send_mult = 0; /* don't try to overflow peer */
- }
- else
- {
- if(length > tcpcb->sndwnd - (tcpcb->sndact - tcpcb->snduna))
- {
- #ifdef DEBUG
- sprintf(str," tcp_send: length exceeds permitted window (%ld) %ld/%ld - truncated \n",tcpcb->sndwnd,length,tcpcb->sndwnd - (tcpcb->sndact - tcpcb->snduna));
- TRACE(str);
- #endif
- length = tcpcb->sndwnd - (tcpcb->sndact - tcpcb->snduna);
- tmpflags &= ~(TCP_PUSH | TCP_URG | TCP_FIN);
- send_mult = 0; /* don't try to overflow peer */
- }
- else
- {
- if( !(tcp_seg->flags & (TCP_PUSH | TCP_FIN)) &&
- length < min(min(tcpcb->maxseg,tcpcb->sndmax/2),tcpcb->q_out.size*3/4))
- {
- #ifdef DEBUG
- sprintf(str,"<tcp_send: packet delayed len %ld < wnd = %d, max/2 = %d\n",length,tcpcb->sndwnd,tcpcb->sndmax/2);
- TRACE(str);
- #endif
- return(0);
- }
- }
- }
- }
- #ifdef DEBUG
- else
- TRACE(" tcp_send: empty packet\n");
- #endif
-
- pkt = ip_alloc((int)MAXTCPSEG,0);
-
- if(!pkt)
- {
- #ifdef DEBUG
- TRACE("<tcp_send no free packet\n");
- #endif
- return(-1); /* no packet free, can't send */
- }
- #ifdef DEBUGPKT
- sprintf(str,"tcp_send: allocated pkt at %lx\n",(long)pkt);
- TRACE(str);
- #endif
-
- tcp = (TCP *)ip_data(pkt);
- tcp->src_port = tcpcb->lcl_port;
- tcp->dst_port = tcpcb->fgn_port;
- tcp->seq = tcpcb->sndact;
- tcp->ack = tcpcb->rcvnxt;
- tcp->doffs = TCP_DATAOFFS;
-
- if(tmpflags & TCP_SYN)
- {
- tcp->doffs += TCP_DATAOFFSINCR;
- ((TCP_PACKET *)pkt)->opt = tcp_option(TCP_OPTMAXSEG,4,MYMAXTCPSEG);
- }
-
- tcp->flags = (u_char)tmpflags;
- tcp->window = tcpcb->rcvwnd;
- #ifdef DEBUG
- sprintf(str," tcp_send: l.%u: len=%lu,sndwnd=%u,rcvwnd=%u,seq=%lx,ack=%lx,sndact=%lx:%s\n",
- tcp->src_port,length,tcpcb->sndwnd,tcp->window,
- tcp->seq,tcp->ack,tcpcb->sndact,pr_flags(tmpflags));
- TRACE(str);
- #endif
- if(tcp->flags & TCP_URG) tcp->urgent = 1 /*tcpcb->sndup*/;
- else tcp->urgent = 0;
- if(length)
- {
- data = (char *)tcp + tcp_hdrlen(tcp);
- #ifdef DEBUG
- sprintf(str," tcp_send: senddata[0] = %02x\n",*data);
- TRACE(str);
- #endif
- q_get(&tcpcb->q_out,(u_char *)data,length,offset);
- }
-
- tcp_ph.dst = tcpcb->fhost;
- tcp_ph.src = ip_myaddr();
- tcp_ph.protocol = IP_TCP;
- tcp_ph.length = tcp_hdrlen(tcp) + length;
-
- tcp->chksum = 0;
- csum = ~chksum((u_short *)&tcp_ph,(int)sizeof(TCP_PSEUDO),0);
- tcp->chksum = chksum((u_short *)tcp,tcp_ph.length,csum);
- if(!tcp->chksum) tcp->chksum = ~tcp->chksum;
-
- tcp_counts[1]++;
- ret = ip_send(IP_TCP,pkt,tcp_ph.length,tcpcb->fhost);
- ip_free(pkt);
-
- tm_stop(tcpcb->tcp_ack);
- tm_stop(tcpcb->tcp_tmresend);
- tm_set(TCP_RETRANSMIT,tcp_retransmitter,tcpcb->tcp_tmresend);
-
- if(ret < 0)
- {
- #ifdef DEBUG
- sprintf(str,"<tcp_send: network error %d\n",ret);
- TRACE(str);
- #endif
- return(ret); /* network error, couldn't send */
- }
-
- tcpcb->sndact += length;
- offset += length;
- if(tmpflags & (TCP_SYN | TCP_FIN)) tcpcb->sndact++;
- if(length == tcp_seg->length) tcp_seg->flags &= ~TCP_UNSENT;
-
- #ifdef DEBUG
- sprintf(str," tcp_send: pkt[%d] to %08lx; %s %s\n",
- tcp_ph.length,tcpcb->fhost,pr_flags(tcp_seg->flags),pr_state(tcpcb));
- TRACE(str);
- #endif
-
- if((tcp_seg->flags & ~(TCP_PUSH | TCP_URG)) == TCP_ACK && tcp_seg->length == 0)
- { /* drop a empty ACK segment */
- #ifdef DEBUG
- sprintf(str," tcp_send: dropped empty ACK packet,tcp_seg = %lx\n",tcp_seg);
- TRACE(str);
- #endif
- tm_stop(tcpcb->tcp_tmresend);
- tcpcb->resend = tcp_seg->next;
- freemem(tcp_seg);
- tcp_seg = tcpcb->resend;
- }
- if(!send_mult) break;
-
- } /* send again ?! */
-
- #ifdef DEBUG
- TRACE("<tcp_send\n");
- #endif
- return(ret);
- }
-
- static int tcp_reset(PACKET *pkt,int len,INADDR fhost, u_short lcl_port)
- { /* send a reset */
- TCP *tcp;
- TCP_PSEUDO tcp_ph;
- u_short csum;
-
- #ifdef DEBUG
- TRACE(">tcp_reset\n");
- #endif
- tcp = (TCP *)ip_data(pkt);
- #ifdef DEBUG
- sprintf(str,">>tcp_reset.l_%u\n",lcl_port);
- TRACE(str);
- #endif
- if(tcp->flags & TCP_RST) return(TRUE); /* received packet has RST */
-
- if(tcp->flags & TCP_ACK)
- {
- tcp->seq = tcp->ack;
- if((tcp->flags & TCP_SYN) || (tcp->flags & TCP_FIN))
- tcp->ack++;
- tcp->flags = TCP_RST;
- }
- else
- {
- tcp->ack = tcp->seq + (u_long)(len - tcp_hdrlen(tcp));
- if(tcp->flags & (TCP_SYN | TCP_FIN))
- tcp->ack++;
- tcp->seq = 0L;
- tcp->flags = TCP_RST | TCP_ACK;
- }
- tcp->dst_port = tcp->src_port;
- tcp->src_port = lcl_port;
-
- tcp_ph.dst = fhost;
- tcp_ph.src = ip_myaddr();
- tcp_ph.protocol = IP_TCP;
- tcp_ph.length = tcp_hdrlen(tcp);
-
- tcp->chksum = 0;
- csum = ~chksum((u_short *)&tcp_ph,(int)sizeof(TCP_PSEUDO),0);
- tcp->chksum = chksum((u_short *)tcp,tcp_ph.length,csum);
- if(!tcp->chksum) tcp->chksum = ~tcp->chksum;
- #ifdef DEBUG
- TRACE("<>tcp_reset\n");
- #endif
-
- tcp_counts[1]++;
- return(ip_send(IP_TCP,pkt,tcp_ph.length,fhost));
- }
-
- int tcp_create(long inbuffersize,long outbuffersize,
- TCP_UPCALL upcall)
- {
- TCP_TCB *tcpcb;
- int i;
-
- #ifdef DEBUG
- TRACE(">tcp_create\n");
- #endif
- if(!tcpcb_tab)
- {
- #ifdef DEBUG
- TRACE("<tcp_create, no tab\n");
- #endif
- return(-1);
- }
- tcpcb = (TCP_TCB *)buf_alloc(tcp_buffers,sizeof(TCP_TCB)+inbuffersize+INBUFBASE+OUTBUFSIZE+2);
- if(!tcpcb)
- {
- #ifdef DEBUG
- TRACE("<tcp_create, no buf\n");
- #endif
- return(-1);
- }
- tcpcb->next = NULL;
- tcpcb->active = FALSE;
- tcpcb->lcl_port = 0;
- tcpcb->fgn_port = 0;
- tcpcb->state = TCP_CLOSED;
- tcpcb->fhost = 0L;
- tcpcb->resend = NULL;
- q_init(&tcpcb->q_out,((char *)tcpcb)+sizeof(TCP_TCB),OUTBUFSIZE+1);
- q_init(&tcpcb->q_in,((char *)tcpcb)+sizeof(TCP_TCB)+OUTBUFSIZE+1,inbuffersize+INBUFBASE+1);
- tcpcb->maxseg = MYMAXTCPSEG;
- tcpcb->snduna = 0L;
- tcpcb->sndnxt = 0L;
- tcpcb->sndact = 0L;
- tcpcb->sndmax = 0;
- tcpcb->sndwnd = 0;
- tcpcb->sndest = 0;
- tcpcb->sndup = 0L;
- tcpcb->sndwl1 = 0L;
- tcpcb->sndwl2 = 0L;
- tcpcb->sndiss = 0L;
-
- tcpcb->rcvnxt = 0L;
- tcpcb->rcvwnd = (u_short)abs(inbuffersize);
- tcpcb->rcvact = (u_short)abs(inbuffersize);
- tcpcb->rcvup = 0;
- tcpcb->rcvdlen = 0;
- tcpcb->timeout = 0L;
- tcpcb->tcp_tm = tm_alloc();
- tcpcb->tcp_ack = tm_alloc();
- tcpcb->tcp_tmresend = tm_alloc();
- tcpcb->upcall = upcall;
-
- for(i=0; i<tcpcb_tablen; i++)
- {
- if(!tcpcb_tab[i])
- {
- tcpcb_tab[i] = tcpcb;
- tcpcb->handle = i;
- #ifdef DEBUG
- TRACE("<tcp_create, ok\n");
- #endif
- return(i);
- }
- }
- #ifdef DEBUG
- TRACE("<tcp_create, error\n");
- #endif
- return(-1);
- }
-
- /* assign a number to local port */
- int tcp_bind(int tcpcb,u_short lcl_port)
- {
- TCP_TCB *ptcpcb;
-
- #ifdef DEBUG
- TRACE(">tcp_bind\n");
- #endif
-
- if(tcpcb<0 || tcpcb >= tcpcb_tablen) return(-1);
- for(ptcpcb = tcpcb_list; ptcpcb; ptcpcb = ptcpcb->next)
- if(ptcpcb->lcl_port == lcl_port)
- {
- if(ptcpcb->state == TCP_TIMEWT)
- {
- #ifdef DEBUG
- TRACE("<tcp_bind, deleting timewaiting tcpcb\n");
- #endif
- /* tcp_delete(ptcpcb->handle);*/
-
- /* was passiert eigentlich mit ptcpcb->next wenn ptcpcb gelöscht wird ? */
- }
- else
- {
- #ifdef DEBUG
- TRACE("<tcp_bind, already in use\n");
- #endif
- return(-1);
- }
- }
- ptcpcb = tcpcb_tab[tcpcb];
- if(!ptcpcb || ptcpcb->next || ptcpcb->state != TCP_CLOSED)
- {
- #ifdef DEBUG
- TRACE("<tcp_create, not exist\n");
- #endif
- return(-1); /* tcpcb does not exist or already in use */
- }
-
- ptcpcb->lcl_port = lcl_port;
- #ifdef DEBUG
- sprintf(str,">>tcp_bind.l_%u.f_%u\n",ptcpcb->lcl_port,ptcpcb->fgn_port);
- TRACE(str);
- #endif
- #ifdef DEBUG
- TRACE("<tcp_bind, ok\n");
- #endif
- return(tcpcb);
- }
-
- TCP_TCB *tcp_gettcb(int tcpcb)
- {
- TCP_TCB *ptcpcb;
-
- if(tcpcb<0 || tcpcb >= tcpcb_tablen) return(NULL);
- ptcpcb = tcpcb_tab[tcpcb];
- return(ptcpcb);
- }
-
- int tcp_open(int handle,INADDR fhost,u_short fport,u_long timeout)
- {
- TCP_TCB *tcpcb;
- TCP_SEGMENT *tcp_seg;
- int ret;
-
- #ifdef DEBUG
- sprintf(str,">tcp_open handle %u f_%u tmout %lu, tablen = %d\n",handle,fport,tcpcb_tablen,timeout);
- TRACE(str);
- #endif
-
- if(handle < 0 || handle >= tcpcb_tablen)
- {
- #ifdef DEBUG
- TRACE("<tcp_open, inv handle\n");
- #endif
- return(-1);
- }
- tcpcb = tcpcb_tab[handle];
- if(!tcpcb || tcpcb->next || tcpcb->state != TCP_CLOSED)
- {
- #ifdef DEBUG
- TRACE("<tcp_open, not exist\n");
- #endif
- return(-1); /* tcpcb does not exist or already in use */
- }
- if(!tcpcb->lcl_port) tcpcb->lcl_port = tcp_newport();
- tcpcb->fgn_port = fport;
- tcpcb->state = TCP_SYNSENT;
- tcpcb->fhost = fhost;
- tcpcb->snduna = tcp_iss();
- tcpcb->sndnxt = tcpcb->snduna+1;
- tcpcb->sndact = tcpcb->snduna;
- tcpcb->sndmax = 0;
- tcpcb->sndiss = tcpcb->snduna;
- tcpcb->timeout = timeout;
- tcpcb->active = TRUE;
-
- #ifdef DEBUG
- sprintf(str,">>tcp_open.l_%u.f_%u\n",tcpcb->lcl_port,tcpcb->fgn_port);
- TRACE(str);
- #endif
-
- tcpcb->next = tcpcb_list; /* put into connections list */
- tcpcb_list = tcpcb;
-
- tcp_seg = tcp_createseg(0,tcpcb->sndiss,TCP_SYN);
- tcp_putseg(tcpcb,tcp_seg); /* put segment in retransmission queue */
- tm_set(TCP_OPENTIMEOUT,tcp_opentimeout,tcpcb->tcp_tm);
-
- #ifdef DEBUGSENDCALL
- sprintf(str,"TCP: call send from line %d\n",__LINE__);
- TRACE(str);
- #endif
-
- ret = tcp_send(tcpcb);
- if(ret < 0)
- {
- #ifdef DEBUG
- TRACE("<tcp_open, network error\n");
- #endif
- return(ret);
- }
-
- #ifdef DEBUG
- tcpcb = tcpcb_list;
- TRACE("Open TCBs\n");
- while(tcpcb)
- {
- sprintf(str,"handle = %d, l_%u.f_%u\n",tcpcb->handle,tcpcb->lcl_port,tcpcb->fgn_port);
- TRACE(str);
- tcpcb = tcpcb->next;
- }
- #endif
-
- #ifdef DEBUG
- TRACE("<tcp_open, ok\n");
- #endif
-
- return(handle);
- }
-
- void tcp_opentimeout(TIMER tm)
- {
- int handle;
-
- #ifdef DEBUG
- TRACE(">tcp_opentimeout\n");
- #endif
-
- for(handle = 0; handle < tcpcb_tablen; handle++)
- if(tcpcb_tab[handle] && tcpcb_tab[handle]->tcp_tm == tm)
- {
- #ifdef DEBUG
- sprintf(str,"opentimeout expired: handle %d\n",handle);
- TRACE(str);
- #endif
- /*tcpcb_tab[handle]->upcall(handle,NULL,TCP_UCTIMEOUT);*/
- tcp_delete(handle);
- #ifdef DEBUG
- TRACE("<tcp_opentimeout, tcpcb deleted\n");
- #endif
- return;
- }
- #ifdef DEBUG
- TRACE("<tcp_opentimeout, no tcpcb\n");
- #endif
- }
-
- int tcp_listen(int handle,u_short lcl_port, u_long timeout)
- {
- TCP_TCB *tcpcb;
-
- #ifdef DEBUG
- sprintf(str,">tcp_listen.l_%u\n",lcl_port);
- TRACE(str);
- #endif
-
- if(handle < 0 || handle >= tcpcb_tablen)
- {
- #ifdef DEBUG
- TRACE("<tcp_listen, inv handle\n");
- #endif
- return(-1);
- }
- if(!lcl_port)
- lcl_port = tcp_newport();
-
- for(tcpcb = tcpcb_list; tcpcb; tcpcb = tcpcb->next)
- if(!tcpcb->active && tcpcb->lcl_port == lcl_port)
- {
- #ifdef DEBUG
- TRACE("<tcp_listen, port in use\n");
- #endif
- return(-1);
- }
- tcpcb = tcpcb_tab[handle];
- if(!tcpcb || tcpcb->next || tcpcb->state != TCP_CLOSED)
- {
- #ifdef DEBUG
- TRACE("tcp_listen, tcpcb not exist\n");
- #endif
- return(-1); /* tcpcb does not exist or already in use */
- }
- tcpcb->active = FALSE;
- tcpcb->lcl_port = lcl_port;
- tcpcb->fgn_port = 0;
- tcpcb->state = TCP_LISTEN;
- tcpcb->fhost = 0L;
- tcpcb->timeout = timeout;
- if(timeout) tm_set(tm_msec(timeout),tcp_opentimeout,tcpcb->tcp_tm);
-
- tcpcb->next = tcpcb_list;
- tcpcb_list = tcpcb; /* put into connections list */
- #ifdef DEBUG
- tcpcb = tcpcb_list;
- TRACE("Listen TCBs\n");
- while(tcpcb)
- {
- sprintf(str,"handle = %d, port l_%u.f_%u\n",tcpcb->handle,tcpcb->lcl_port,tcpcb->fgn_port);
- TRACE(str);
- tcpcb = tcpcb->next;
- }
- #endif
- #ifdef DEBUG
- TRACE("<tcp_listen, ok\n");
- #endif
- return(handle);
- }
-
- int tcp_delete(int tcpcb)
- {
- TCP_SEGMENT *seg, *tcp_seg;
- TCP_TCB **b,*ptcpcb;
-
- #ifdef DEBUG
- TRACE("<tcp_delete\n");
- #endif
-
- if(tcpcb<0 || tcpcb >= tcpcb_tablen)
- {
- #ifdef DEBUG
- TRACE("<tcp_delete, inv handle\n");
- #endif
- return(-1);
- }
- ptcpcb = tcpcb_tab[tcpcb];
- if(!ptcpcb)
- {
- #ifdef DEBUG
- TRACE("<tcp_delete, tcpcb does not exist\n");
- #endif
- return(-1); /* tcpcb does not exist */
- }
- #ifdef DEBUG
- sprintf(str,">>tcp_delete.l_%u.f_%u\n",ptcpcb->lcl_port,ptcpcb->fgn_port);
- TRACE(str);
- #endif
- tcpcb_tab[tcpcb] = NULL;
- tcp_seg = ptcpcb->resend;
- while(tcp_seg)
- {
- seg = tcp_seg->next;
- freemem(tcp_seg); /* free all pending segments */
- tcp_seg = seg;
- }
- tm_free(ptcpcb->tcp_tm); /* free timer */
- tm_free(ptcpcb->tcp_ack); /* free timer */
- tm_free(ptcpcb->tcp_tmresend); /* free resend timer */
- b = &tcpcb_list;
- while(*b)
- {
- if(*b == ptcpcb) break;
- b = &(*b)->next;
- }
- if(*b) *b = (*b)->next;
- if(!buf_free(tcp_buffers,(char *)ptcpcb))
- #ifdef DEBUGBUF
- TRACE("TCP: buf_free failed\n");
- #endif
- ; /* free control block */
- #ifdef DEBUG
- ptcpcb = tcpcb_list;
- TRACE("Remaining TCBs\n");
- while(ptcpcb)
- {
- sprintf(str,"handle = %d, port l_%u.f_%u\n",ptcpcb->handle,ptcpcb->lcl_port,ptcpcb->fgn_port);
- TRACE(str);
- ptcpcb = ptcpcb->next;
- }
- #endif
- #ifdef DEBUG
- TRACE("<tcp_delete, ok\n");
- #endif
- return(TRUE);
- }
-
- int tcp_close(int tcpcb)
- {
- TCP_TCB *ptcpcb;
- TCP_SEGMENT *tcp_seg;
-
- #ifdef DEBUG
- TRACE(">tcp_close\n");
- #endif
-
- if(tcpcb < 0 || tcpcb >= tcpcb_tablen)
- {
- #ifdef DEBUG
- TRACE("<tcp_close, inv handle\n");
- #endif
- return(-1);
- }
- ptcpcb = tcpcb_tab[tcpcb];
- if(!ptcpcb)
- {
- #ifdef DEBUG
- TRACE("<tcp_close, tcpcb does not exist\n");
- #endif
- return(-1); /* tcpcb does not exist */
- }
- #ifdef DEBUG
- sprintf(str,">>tcp_close.l_%u.f_%u\n",ptcpcb->lcl_port,ptcpcb->fgn_port);
- TRACE(str);
- TRACE(pr_state(ptcpcb));
- #endif
-
- switch(ptcpcb->state)
- {
- case TCP_LISTEN:
- case TCP_SYNSENT:
- /*ptcpcb->upcall(tcpcb,NULL,TCP_UCCLOSING);*/
- tcp_delete(tcpcb);
- #ifdef DEBUG
- TRACE("<tcp_close, LISTEN or SYNSENT state, tcpcb deleted\n");
- #endif
- return(FALSE);
-
- case TCP_SYNREC:
- case TCP_ESTAB:
- case TCP_CLOSEWT:
- tcp_seg = tcp_createseg(0,ptcpcb->sndnxt++,TCP_FIN | TCP_ACK);
- ptcpcb->finack = ptcpcb->sndnxt;
- tcp_putseg(ptcpcb,tcp_seg);
- #ifdef DEBUGSENDCALL
- sprintf(str,"TCP: call send from line %d\n",__LINE__);
- TRACE(str);
- #endif
- tcp_send(ptcpcb);
- if(ptcpcb->state == TCP_CLOSEWT)
- {
- ptcpcb->state = TCP_LASTACK;
- #ifdef DEBUG
- TRACE("<tcp_close, -> TCP_LASTACK\n");
- #endif
- }
- else
- {
- ptcpcb->state = TCP_FINWT1;
- printf("\a");
- #ifdef DEBUG
- TRACE("<tcp_close, -> TCP_FINWT1\n");
- #endif
- }
- return(TRUE);
-
- default:
- #ifdef DEBUG
- TRACE("<tcp_close, already closing\n");
- #endif
- return(-1); /* error, closing */
- }
- }
-
- int tcp_abort(int tcpcb)
- {
- PACKET *pkt;
- TCP_TCB *ptcpcb;
- TCP *tcp;
-
- #ifdef DEBUG
- TRACE(">tcp_abort\n");
- #endif
-
- if(tcpcb<0 || tcpcb >= tcpcb_tablen)
- {
- #ifdef DEBUG
- TRACE("<tcp_abort, inv handle\n");
- #endif
- return(-1);
- }
- ptcpcb = tcpcb_tab[tcpcb];
- if(!ptcpcb || ptcpcb->state == TCP_CLOSED)
- {
- #ifdef DEBUG
- TRACE("<tcp_abort, tcpcb does not exist\n");
- #endif
- return(-1); /* tcpcb does not exist */
- }
- #ifdef DEBUG
- sprintf(str,">>tcp_abort.l_%u.f_%u\n",ptcpcb->lcl_port,ptcpcb->fgn_port);
- TRACE(str);
- #endif
- switch(ptcpcb->state)
- {
- case TCP_SYNREC:
- case TCP_ESTAB:
- case TCP_FINWT1:
- case TCP_FINWT2:
- case TCP_CLOSEWT:
- pkt = ip_alloc((int)sizeof(TCP),0);
- if(pkt)
- {
- #ifdef DEBUG
- sprintf(str,"aborting connection to 0x%08lx.l_%d\n",ptcpcb->fhost,ptcpcb->lcl_port);
- TRACE(str);
- #endif
- tcp = (TCP *)ip_data(pkt);
- tcp->flags = TCP_ACK;
- tcp->src_port = ptcpcb->fgn_port;
- tcp_reset(pkt,(int)sizeof(TCP),ptcpcb->fhost,ptcpcb->lcl_port);
- ip_free(pkt);
- }
- else return(-1);
- break;
- }
- tcp_delete(tcpcb);
- #ifdef DEBUG
- TRACE("<tcp_abort, tcpcb deleted\n");
- #endif
- return(TRUE);
- }
-
- long tcp_read(int tcpcb,char *buffer,u_short length)
- {
- TCP_TCB *ptcpcb;
- TCP_SEGMENT *tcp_seg;
- long len;
- u_short cur_rcvwnd;
-
- #ifdef DEBUG
- TRACE(">tcp_read\n");
- #endif
-
- if(tcpcb < 0 || tcpcb >= tcpcb_tablen)
- {
-
- #ifdef DEBUG
- TRACE("<tcp_read, inv handle\n");
- #endif
- return(-1L);
- }
- ptcpcb = tcpcb_tab[tcpcb];
- if(!ptcpcb)
- {
- #ifdef DEBUG
- TRACE("<tcp_read, tcpcb does not exist\n");
- #endif
- return(-1L); /* tcpcb does not exist or already in use */
-
- }
- #ifdef DEBUG
- sprintf(str," tcp_read: l_%u.f_%u\n",ptcpcb->lcl_port,ptcpcb->fgn_port);
- TRACE(str);
- #endif
-
- cur_rcvwnd = ptcpcb->rcvwnd;
-
- switch(ptcpcb->state)
- {
- case TCP_CLOSED:
- return(-2L);
-
- case TCP_LISTEN:
- case TCP_SYNSENT:
- case TCP_SYNREC:
- return(0L);
-
- case TCP_ESTAB:
- case TCP_FINWT1:
- case TCP_FINWT2:
- case TCP_CLOSEWT:
- len = q_used(&ptcpcb->q_in);
- #ifdef DEBUG
- sprintf(str," tcp_read: rd = %lx wr = %lx -> %ld bytes in queue\n",(&ptcpcb->q_in)->rd,(&ptcpcb->q_in)->wr,len);
- TRACE(str);
- #endif
-
- if(!len && !ptcpcb->resend)
- {
- /* ptcpcb->rcvwnd = tcp_rcvwindow(ptcpcb);
- tcp_seg = tcp_createseg(0,ptcpcb->sndnxt,TCP_ACK);
- tcp_putseg(ptcpcb,tcp_seg);
- tm_stop(ptcpcb->tcp_tmresend);
- tm_set(TCP_RETRANSMIT,tcp_retransmitter,ptcpcb->tcp_tmresend);*/
-
- #ifdef DEBUG
- TRACE("<tcp_read, no data\n");
- #endif
- if(ptcpcb->state == TCP_CLOSEWT)
- return(-1L); /* EOF */
- else
- return(0L);
- }
- #ifdef DEBUG
- TRACE(" tcp_read: get data\n");
- #endif
-
- if(len < length) length = (u_short)len;
- q_get(&ptcpcb->q_in,(u_char *)buffer,length,0);
- q_rem(&ptcpcb->q_in,length);
-
- ptcpcb->rcvwnd = tcp_rcvwindow(ptcpcb);
- ptcpcb->rcvdlen = q_used(&ptcpcb->q_in);
-
- if(cur_rcvwnd == 0 && ptcpcb->rcvwnd != 0)
- {
- #ifdef DEBUG
- TRACE(" tcp_read: create ackseg\n");
- #endif
- tcp_seg = tcp_createseg(0,ptcpcb->sndnxt,TCP_ACK);
- tcp_putseg(ptcpcb,tcp_seg);
- tm_stop(ptcpcb->tcp_ack);
- /*tcp_acktimeout*/(tm_set(TCP_NODELAY,tcp_acktimeout,ptcpcb->tcp_ack));
- /* send immediate ack */
-
- }
- #ifdef DEBUG
- TRACE("<tcp_read, ok\n");
- #endif
- return((long)length);
-
- case TCP_CLOSING:
- case TCP_LASTACK:
- case TCP_TIMEWT:
- return(-2L);
- }
- return(-2L);
- }
-
- long tcp_write(int tcpcb,char *buffer,u_short length, u_char flags)
- {
- TCP_TCB *ptcpcb;
- TCP_SEGMENT *tcp_seg;
- long len;
- int ret;
-
- #ifdef DEBUG
- TRACE(">tcp_write\n");
- #endif
-
- flags &= (TCP_PUSH | TCP_URG);
- if(tcpcb<0 || tcpcb >= tcpcb_tablen)
- {
- #ifdef DEBUG
- TRACE("<tcp_write, inv handle\n");
- #endif
- return(-1L);
- }
- ptcpcb = tcpcb_tab[tcpcb];
- if(!ptcpcb || ptcpcb->state == TCP_CLOSED)
- {
- #ifdef DEBUG
- TRACE("<tcp_write, tcpcb does not exist\n");
- #endif
- return(-1L); /* tcpcb does not exist or already in use */
- }
- #ifdef DEBUG
- sprintf(str," >>tcp_write: l_%u.f_%u %d bytes\n",ptcpcb->lcl_port,ptcpcb->fgn_port,length);
- TRACE(str);
- #endif
- if(q_free(&ptcpcb->q_out) < length)
- {
- length = q_free(&ptcpcb->q_out);
- flags &= ~TCP_PUSH;
- #ifdef DEBUG
- TRACE("<tcp_write:putbuffer full\n");
- #endif
- }
- if(length == 0 && !(flags & TCP_URG)) return 0L;
-
- #ifdef DEBUG
- sprintf(str," tcp_write: try to send %u bytes\n",length);
- TRACE(str);
- #endif
- switch(ptcpcb->state)
- {
- case TCP_LISTEN:
-
- case TCP_SYNSENT:
- case TCP_SYNREC:
- #ifdef DEBUG
- TRACE("<tcp_write, inv state, send not allowed\n");
- #endif
- return(-1L);
-
- case TCP_ESTAB:
- case TCP_CLOSEWT:
- len = length;
- tcp_seg = tcp_createseg(len,ptcpcb->sndnxt,TCP_ACK | flags);
- if(!tcp_seg)
- {
- #ifdef DEBUG
- TRACE("<tcp_write, cannot create segment\n");
- #endif
- return(0L);
- }
- #ifdef DEBUG
- sprintf(str," tcp_write: put segment: %ld bytes senddata[0]=%02x seq=%lx\n",len,buffer[0],ptcpcb->sndnxt);
- TRACE(str);
- #endif
- tcp_putseg(ptcpcb,tcp_seg);
- q_put(&ptcpcb->q_out,(u_char *)buffer,len);
- ptcpcb->sndnxt += len;
-
- if((flags & TCP_PUSH) || (q_free(&ptcpcb->q_out) < (ptcpcb->q_out.size / 4)))
- {
- #ifdef DEBUGSENDCALL
- sprintf(str,"TCP: call send from line %d\n",__LINE__);
- TRACE(str);
- #endif
- ret = tcp_send(ptcpcb); /* resend can't be NULL */
- if(ret < 0)
- {
- #ifdef DEBUG
- TRACE("<tcp_write, error\n");
- #endif
- return((long)ret); /* report error */
- }
- }
- #ifdef DEBUG
- TRACE("<tcp_write, ok\n");
- #endif
- return(length);
-
- default:
- #ifdef DEBUG
- TRACE("<tcp_write, error, already closing\n");
- #endif
- return(-1L);
- }
- }
-
- u_short tcp_newport(void)
- {
- static u_short act_port = 0;
- TCP_TCB *ptcpcb;
-
- #ifdef DEBUG
- TRACE(">tcp_newport\n");
- #endif
- do
- {
- if(!act_port)
- act_port = (u_short)clock();
- else
- act_port++;
- if(act_port < 1200) act_port += 1200;
- for(ptcpcb = tcpcb_list; ptcpcb; ptcpcb = ptcpcb->next) /* search, if port locally used */
- if(ptcpcb->lcl_port == act_port) break;
- }
- while(ptcpcb);
-
- #ifdef DEBUG
- TRACE("<tcp_newport\n");
- #endif
- return(act_port);
- }
-
- void tcp_retransmitter(TIMER tm)
- {
- TCP_TCB *tcpcb;
- #ifdef DEBUG
- sprintf(str,">tcp_retransmitter %d\n",mode);
- TRACE(str);
- #endif
-
- for(tcpcb = tcpcb_list; tcpcb; tcpcb = tcpcb->next)
- {
- if(tm == tcpcb->tcp_tmresend && tcpcb->resend)
- {
- tcpcb->sndact = tcpcb->snduna; /* back off to start of retransmit queue */
- #ifdef DEBUG
- sprintf(str," retransmit for handle %d\n",tcpcb->handle);
- TRACE(str);
- #endif
- #ifdef DEBUGSENDCALL
- sprintf(str," tcpretransmit: call send for l_%ud f_%ud\n",tcpcb->lcl_port,tcpcb->fgn_port);
- TRACE(str);
- #endif
- tcp_send(tcpcb);
- #ifdef DEBUG
- TRACE("<tcp_retransmitter, ok\n");
- #endif
- return;
- }
- }
- #ifdef DEBUG
- sprintf(str,"<tcp_retransmitter.timer_%u, tcpcb not found\n",tm);
- TRACE(str);
- #endif
- }
-
- void tcp_acktimeout(TIMER tm)
- {
- TCP_TCB *tcpcb;
-
- #ifdef DEBUG
- TRACE(">tcp_acktimeout\n");
- #endif
-
- for(tcpcb = tcpcb_list; tcpcb; tcpcb = tcpcb->next)
- {
- if(tcpcb->tcp_ack == tm)
- {
- #ifdef DEBUGSENDCALL
- sprintf(str,"tcpacktimeout: call send for l_%ud f_%ud\n",tcpcb->lcl_port,tcpcb->fgn_port);
- TRACE(str);
- #endif
- tcp_send(tcpcb);
- #ifdef DEBUG
- TRACE("<tcp_acktimeout, ok\n");
- #endif
- return;
- }
- }
- #ifdef DEBUG
- sprintf(str,"<tcp_acktimeout.timer_%u: tcpcb not found\n",tm);
- TRACE(str);
- #endif
- }
-
- void tcp_expedittm(TIMER tm)
- {
- TCP_TCB *tcpcb;
- #ifdef DEBUG
- TRACE(">tcp_expedittm\n");
- #endif
-
- tcpcb = tcpcb_list;
- while(tcpcb)
- {
- if(tcpcb->resend)
- {
- #ifdef DEBUGSENDCALL
- sprintf(str,"tcpexpedit: call send for l_%ud f_%ud\n",tcpcb->lcl_port,tcpcb->fgn_port);
- TRACE(str);
- #endif
- tcp_send(tcpcb);
- }
- tcpcb = tcpcb->next;
- }
- tm_set(TCP_EXPEDIT,tcp_expedittm,tm);
- #ifdef DEBUG
- TRACE("<tcp_expedittm, ok\n");
- #endif
- }
-
- void tcp_timewait(TIMER tm)
- {
- TCP_TCB *tcpcb;
- #ifdef DEBUG
- TRACE(">tcp_timewait\n");
- #endif
- for(tcpcb = tcpcb_list; tcpcb; tcpcb = tcpcb->next)
- {
- if(tcpcb->state == TCP_TIMEWT && tcpcb->tcp_tm == tm)
- {
- /*tcpcb->upcall(tcpcb->handle,NULL,TCP_UCCLOSED);*/
- tcp_delete(tcpcb->handle);
- #ifdef DEBUGTIMEW
- sprintf(str,"TCP: timewait tcpcb handle %d deleted\n",tcpcb->handle);
- TRACE(str);
- #endif
- return;
- }
- }
- #ifdef DEBUG
- TRACE("tcp_timewait, no tcpcb found\n");
- #endif
- }
-
- u_short tcp_rcvwindow(TCP_TCB *tcpcb)
- {
- short win;
- u_short mywind;
-
- #ifdef DEBUGRWIN
- sprintf(str,">tcp_rcvwindow.l_%u.f_%u qsize=%ul\n",tcpcb->lcl_port,tcpcb->fgn_port,tcpcb->q_in.size);
- TRACE(str);
- #endif
-
- mywind = tcpcb->rcvact = (u_short)q_free(&(tcpcb->q_in));
-
- win = tcpcb->rcvact - tcpcb->rcvwnd;
-
- if(win > 0) /* more space */
- {
- if(win < MYMAXTCPSEG && MYMAXTCPSEG < tcpcb->q_in.size)
- {
- #ifdef DEBUGRWIN
- sprintf(str,"<tcp_rcvwindow rcvact=%u rcvwnd=%u delta=%u new =%u\n",tcpcb->rcvact,tcpcb->rcvwnd,win,tcpcb->rcvwnd);
- TRACE(str);
- #endif
- return(tcpcb->rcvwnd);
- }else
- {
- #ifdef DEBUGRWIN
- sprintf(str,"<tcp_rcvwindow rcvact=%u rcvwnd=%u delta=%u new =%u\n",tcpcb->rcvact,tcpcb->rcvwnd,win,tcpcb->rcvwnd + (min(MYMAXTCPSEG, win)));
- TRACE(str);
- #endif
- mywind = tcpcb->rcvwnd + (min(MYMAXTCPSEG, win));
- mywind = min(mywind,(tcpcb->q_in.size - INBUFBASE - 1)); /* hold receive window artificially closed */
- return mywind;
- }
- }
- else
- {
- if(MYMAXTCPSEG < tcpcb->q_in.size)
- {
- #ifdef DEBUGRWIN
- sprintf(str,"<tcp_rcvwindow rcvact=%u rcvwnd=%u delta=%u new =%u\n",tcpcb->rcvact,tcpcb->rcvwnd,win,MYMAXTCPSEG*(tcpcb->rcvact / MYMAXTCPSEG));
- TRACE(str);
- #endif
- return(MYMAXTCPSEG*(tcpcb->rcvact / MYMAXTCPSEG));
- }
- else
- {
- #ifdef DEBUGRWIN
- sprintf(str,"<tcp_rcvwindow rcvact=%u rcvwnd=%u delta=%u new =%u\n",tcpcb->rcvact,tcpcb->rcvwnd,win,tcpcb->rcvact);
- TRACE(str);
- #endif
- return(tcpcb->rcvact);
- }
- }
- }
-
- int tcp_du_handler(IP *ip)
- {
- TCP_TCB *ptcpcb;
- TCP *tcp;
-
- #ifdef DEBUG
- TRACE(">tcp_du_handler\n");
- #endif
-
- if(!ip)
- {
- #ifdef DEBUG
- TRACE("<tcp_du_handler, invalid ip\n");
- #endif
- return(FALSE);
- }
- tcp = (TCP *)((char *)(ip)+ip_hdrlen(ip));
- ptcpcb = tcpcb_list;
- while(ptcpcb)
- {
- if((ip->dst_inaddr == ptcpcb->fhost) &&
- (ip->src_inaddr == ip_myaddr()) &&
- (tcp->src_port == ptcpcb->lcl_port) &&
- (tcp->dst_port == ptcpcb->fgn_port))
- {
- tcp_delete(ptcpcb->handle);
- #ifdef DEBUG
- TRACE("<tcp_du_handler, killed\n");
- #endif
- return(TRUE);
- }
- ptcpcb = ptcpcb->next;
- }
- #ifdef DEBUG
- TRACE("<tcp_du_handler, not found\n");
- #endif
- return(FALSE);
- }
-
-
-
-
-
-
-
-
- #ifdef DEBUG
-
-
- char *pr_flags(u_char flags)
- {
- static char pr_str[40];
- pr_str[0] = 0;
- if(flags & TCP_FIN) strcat(pr_str,"FIN ");
- if(flags & TCP_SYN) strcat(pr_str,"SYN ");
- if(flags & TCP_RST) strcat(pr_str,"RST ");
- if(flags & TCP_PUSH) strcat(pr_str,"PUSH ");
- if(flags & TCP_ACK) strcat(pr_str,"ACK ");
- if(flags & TCP_URG) strcat(pr_str,"URG ");
- return(pr_str);
- }
-
- char *pr_state(TCP_TCB *tcpcb)
- {
- static char *states[11]=
- {
- "CLOSED",
- "LISTEN",
- "SYNSENT",
- "SYNREC",
- "ESTAB",
- "FINWT1",
- "FINWT2",
- "CLOSEWT",
- "CLOSING",
- "LASTACK",
- "TIMEWT"
- };
- return(states[tcpcb->state]);
- }
- #endif
-